home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / app / dialog_handler.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-12  |  8.2 KB  |  357 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  * Copyright (C) 1999 Andy Thomas (alt@picnic.demon.co.uk)
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18.  */
  19.  
  20. /* Make dialog_handler.h declare the exported entry points from this
  21.  * file for export, to match the definition here.
  22.  */
  23. #define __DIALOG_HANDLER_C_ 1
  24.  
  25. #include <gtk/gtk.h>
  26.  
  27. #include <gmodule.h>
  28.  
  29. #include "apptypes.h"
  30. #include "cursorutil.h"
  31. #include "dialog_handler.h"
  32.  
  33. /*  State of individual dialogs  */
  34.  
  35. typedef enum
  36. {
  37.   INVISIBLE,
  38.   VISIBLE,
  39.   UNKNOWN
  40. } VisibilityState;
  41.  
  42. typedef struct _DialogState DialogState;
  43.  
  44. struct _DialogState
  45. {
  46.   GtkWidget       *dialog;
  47.   VisibilityState  saved_state;
  48. };
  49.  
  50. /*  This keeps track of the state the dialogs are in
  51.  *  ie how many times we have pressed the tab key
  52.  */
  53. typedef enum
  54. {
  55.   SHOW_ALL,
  56.   HIDE_ALL,
  57.   SHOW_TOOLBOX,
  58.   LAST_SHOW_STATE
  59. } ShowState;
  60.  
  61. /*  Start off with all dialogs showing  */
  62. static ShowState dialogs_showing = SHOW_ALL;
  63.  
  64. /*  Prevent multiple keypresses from unsetting me.  */
  65. static gboolean doing_update = FALSE;
  66.  
  67. /*  List of dialogs that have been created and are on screen
  68.  *  (may be hidden already).
  69.  */
  70. static GSList * active_dialogs = NULL;
  71.  
  72. /* Used as a placeholder when a member of active_dialogs is removed due to
  73.  * a detected error. 
  74.  */
  75. static GSList error_tmp_list = { NULL, NULL };
  76.  
  77. /*  Those have a special behaviour  */
  78. static DialogState * toolbox_shell  = NULL;
  79. static DialogState * fileload_shell = NULL;
  80.  
  81. /*  Private  */
  82.  
  83. /*  Hide all currently registered dialogs  */
  84.  
  85. static void
  86. dialog_hide_all (void)
  87. {
  88.   DialogState *dstate;
  89.   GSList *list;
  90.  
  91.   for (list = active_dialogs; list; list = g_slist_next (list))
  92.     {
  93.       dstate = (DialogState *) list->data;
  94.   
  95.       if (GTK_WIDGET_VISIBLE (dstate->dialog))
  96.     {
  97.       dstate->saved_state = VISIBLE;
  98.       gtk_widget_hide (dstate->dialog);
  99.     }
  100.       else
  101.     {
  102.       dstate->saved_state = INVISIBLE;
  103.     }
  104.     }
  105. }
  106.  
  107. /*  Show all currently registered dialogs  */
  108.  
  109. static void
  110. dialog_show_all (void)
  111. {
  112.   DialogState *dstate;
  113.   GSList *list;
  114.  
  115.   for (list = active_dialogs; list; list = g_slist_next (list))
  116.     {
  117.       dstate = (DialogState *) list->data;
  118.  
  119.       if (dstate->saved_state == VISIBLE && !GTK_WIDGET_VISIBLE (dstate->dialog))
  120.     gtk_widget_show(dstate->dialog);
  121.     }
  122. }
  123.  
  124. /*  Handle the tool box in a special way  */
  125.  
  126. static void
  127. dialog_hide_toolbox (void)
  128. {
  129.   if (toolbox_shell && GTK_WIDGET_VISIBLE (toolbox_shell->dialog))
  130.     {
  131.       gtk_widget_hide (toolbox_shell->dialog);
  132.       toolbox_shell->saved_state = VISIBLE;
  133.     }
  134. }
  135.  
  136. /*  public  */
  137.  
  138. void
  139. dialog_show_toolbox (void)
  140. {
  141.   if (toolbox_shell && 
  142.       toolbox_shell->saved_state == VISIBLE && 
  143.       !GTK_WIDGET_VISIBLE (toolbox_shell->dialog))
  144.     {
  145.       gtk_widget_show (toolbox_shell->dialog);
  146.     }
  147. }
  148.  
  149. /*  Set hourglass cursor on all currently registered dialogs  */
  150.  
  151. void
  152. dialog_idle_all (void)
  153. {
  154.   DialogState *dstate;
  155.   GSList *list;
  156.  
  157.   for (list = active_dialogs; list; list = g_slist_next (list))
  158.     {
  159.       dstate = (DialogState *) list->data;
  160.  
  161.       if(!GTK_IS_WIDGET(dstate->dialog) || 
  162.      (GTK_WIDGET_VISIBLE(dstate->dialog) && !dstate->dialog->window))
  163.     {
  164.       g_warning("%s discovered non-widget thing %p in list of "
  165.             "active_dialogs.  Calling dialog_unregister on it.\n",
  166.             G_GNUC_PRETTY_FUNCTION, dstate->dialog);
  167.  
  168.       error_tmp_list.next=list->next;
  169.       list=&error_tmp_list;
  170.       dialog_unregister(dstate->dialog);
  171.     }
  172.       else if(GTK_WIDGET_VISIBLE (dstate->dialog))
  173.     {
  174.       change_win_cursor (dstate->dialog->window, GDK_WATCH,
  175.                  TOOL_TYPE_NONE, CURSOR_MODIFIER_NONE, FALSE);
  176.     }
  177.     }
  178.  
  179.   if (toolbox_shell && GTK_WIDGET_VISIBLE (toolbox_shell->dialog))
  180.     {
  181.       change_win_cursor (toolbox_shell->dialog->window, GDK_WATCH,
  182.              TOOL_TYPE_NONE, CURSOR_MODIFIER_NONE, FALSE);
  183.     }
  184.  
  185.   if (fileload_shell && GTK_WIDGET_VISIBLE (fileload_shell->dialog))
  186.     {
  187.       change_win_cursor (fileload_shell->dialog->window, GDK_WATCH,
  188.              TOOL_TYPE_NONE, CURSOR_MODIFIER_NONE, FALSE);
  189.     }
  190. }
  191.  
  192. /*  And remove the hourglass again.  */
  193.  
  194. void
  195. dialog_unidle_all (void)
  196. {
  197.   DialogState *dstate;
  198.   GSList *list;
  199.  
  200.   for (list = active_dialogs; list; list = g_slist_next (list))
  201.     {
  202.       dstate = (DialogState *) list->data;
  203.  
  204.       if(!GTK_IS_WIDGET(dstate->dialog) || 
  205.      (GTK_WIDGET_VISIBLE(dstate->dialog) && !dstate->dialog->window))
  206.     {
  207.       g_warning("%s discovered non-widget thing %p in list of "
  208.             "active_dialogs.  Calling dialog_unregister on it.\n",
  209.             G_GNUC_PRETTY_FUNCTION, dstate->dialog);
  210.  
  211.       error_tmp_list.next=list->next;
  212.       list=&error_tmp_list;
  213.       dialog_unregister(dstate->dialog);
  214.     }
  215.       else if (GTK_WIDGET_VISIBLE (dstate->dialog))
  216.     {
  217.       unset_win_cursor (dstate->dialog->window);
  218.     }
  219.     }
  220.  
  221.   if (toolbox_shell && GTK_WIDGET_VISIBLE (toolbox_shell->dialog))
  222.     {
  223.       unset_win_cursor (toolbox_shell->dialog->window);
  224.     }
  225.  
  226.   if (fileload_shell && GTK_WIDGET_VISIBLE (fileload_shell->dialog))
  227.     {
  228.       unset_win_cursor (fileload_shell->dialog->window);
  229.     }
  230. }
  231.  
  232. /*  Register a dialog that we can handle  */
  233.  
  234. G_MODULE_EXPORT
  235. void
  236. dialog_register (GtkWidget *dialog)
  237. {
  238.   DialogState *dstate;
  239.  
  240.   dstate = g_new (DialogState, 1);
  241.  
  242.   dstate->dialog      = dialog;
  243.   dstate->saved_state = UNKNOWN;
  244.  
  245.   active_dialogs = g_slist_append (active_dialogs, dstate);
  246. }
  247.  
  248. void
  249. dialog_register_toolbox (GtkWidget *dialog)
  250. {
  251.   toolbox_shell = g_new (DialogState, 1);
  252.  
  253.   toolbox_shell->dialog      = dialog;
  254.   toolbox_shell->saved_state = UNKNOWN;
  255. }
  256.  
  257. void
  258. dialog_register_fileload (GtkWidget *dialog)
  259. {
  260.   fileload_shell = g_new (DialogState, 1);
  261.  
  262.   fileload_shell->dialog      = dialog;
  263.   fileload_shell->saved_state = UNKNOWN;
  264. }
  265.  
  266. /*  unregister dialog  */
  267.  
  268. G_MODULE_EXPORT
  269. void
  270. dialog_unregister (GtkWidget *dialog)
  271. {
  272.   DialogState *dstate = NULL;
  273.   GSList *list;
  274.  
  275.   for (list = active_dialogs; list; list = g_slist_next (list))
  276.     {
  277.       dstate = (DialogState *) list->data;
  278.  
  279.       if (dstate->dialog == dialog)
  280.     break;
  281.     }
  282.  
  283.   if (dstate != NULL)
  284.     {
  285.       active_dialogs = g_slist_remove (active_dialogs, dstate);
  286.       g_free (dstate);
  287.     }
  288. }
  289.  
  290. /*  Toggle showing of dialogs
  291.  *
  292.  *  States:-
  293.  *  SHOW_ALL -> HIDE_ALL -> SHOW_TOOLBOX -> SHOW_ALL ....
  294.  */
  295.  
  296. void 
  297. dialog_toggle (void)
  298. {
  299.   GSList *list;
  300.  
  301.   if (doing_update)
  302.     return;
  303.  
  304.   doing_update = TRUE;
  305.  
  306.   /* Paranoid error checking on our active_dialogs list, because
  307.      3rd party modules access this list through dialog_register 
  308.      and we don't want them wreaking havoc on our internal state.
  309.      Attempts to recover gracefully, but *is not bulletproof* since
  310.      GTK_IS_WIDGET *may* succeed, even if it's pointing to garbage,
  311.      if the garbage looks a little like a widget structure. */
  312.   for (list = active_dialogs; list; list = g_slist_next (list))
  313.     {
  314.       DialogState* dstate = (DialogState *) list->data;
  315.  
  316.       if(!GTK_IS_WIDGET(dstate->dialog))
  317.     {
  318.       g_warning("%s discovered non-widget thing %p in list of "
  319.             "active_dialogs.  Calling dialog_unregister on it.\n",
  320.             G_GNUC_PRETTY_FUNCTION, dstate->dialog);
  321.  
  322.       /* We must find the next list element before the current one
  323.          is destroyed by the call to unregister. */
  324.       error_tmp_list.next=list->next;
  325.       list=&error_tmp_list;
  326.       dialog_unregister(dstate->dialog);
  327.     }
  328.     }
  329.  
  330.   switch (dialogs_showing)
  331.     {
  332.     case SHOW_ALL:
  333.       dialogs_showing = HIDE_ALL;
  334.       dialog_hide_all ();
  335.       dialog_hide_toolbox ();
  336.       break;
  337.     case HIDE_ALL:
  338.       dialogs_showing = SHOW_TOOLBOX;
  339.       dialog_show_toolbox ();
  340.       break;
  341.     case SHOW_TOOLBOX:
  342.       dialogs_showing = SHOW_ALL;
  343.       dialog_show_all ();
  344.     default:
  345.       break;
  346.     }
  347.  
  348.   gdk_flush ();
  349.   while (gtk_events_pending ())
  350.     {
  351.       gtk_main_iteration ();
  352.       gdk_flush ();
  353.     }
  354.  
  355.   doing_update = FALSE;
  356. }
  357.